using System;
using System.Collections;
using System.Collections.Generic;
using LightCAD.MathLib;
using static LightCAD.MathLib.MathEx;

namespace LightCAD.Three
{
    public class InterleavedBufferAttribute : Float32BufferAttribute
    {
        #region scope properties or methods
        //private static Vector3 _vector = new Vector3();
        public InterleavedBufferAttributeContext getContext()
        {
            return ThreeThreadContext.GetCurrThreadContext().InterleavedBufferAttributeCtx;
        }
        #endregion

        #region Properties

        public InterleavedBuffer data;
        public int offset;

        public override int count => this.data.count;
        public override double[] array => this.data.array;
        #endregion

        #region constructor
        public InterleavedBufferAttribute(InterleavedBuffer interleavedBuffer, int itemSize, int offset, bool normalized = false)
        {
            this.name = "";
            this.data = interleavedBuffer;
            this.itemSize = itemSize;
            this.arrObj = this.data.arrObj;
            this.offset = offset;
            this.normalized = normalized;
        }
        #endregion

        #region properties
        #endregion

        #region methods
        public override BufferAttribute applyMatrix4(Matrix4 m)
        {
            var _vector = getContext()._vector;
            for (int i = 0, l = this.data.count; i < l; i++)
            {
                _vector.FromBufferAttribute(this, i);
                _vector.ApplyMatrix4(m);
                this.setXYZ(i, _vector.X, _vector.Y, _vector.Z);
            }
            return this;
        }
        public override BufferAttribute applyNormalMatrix(Matrix3 m)
        {
            var _vector = getContext()._vector;
            for (int i = 0, l = this.count; i < l; i++)
            {
                _vector.FromBufferAttribute(this, i);
                _vector.ApplyNormalMatrix(m);
                this.setXYZ(i, _vector.X, _vector.Y, _vector.Z);
            }
            return this;
        }
        public override BufferAttribute transformDirection(Matrix4 m)
        {
            var _vector = getContext()._vector;
            for (int i = 0, l = this.count; i < l; i++)
            {
                _vector.FromBufferAttribute(this, i);
                _vector.TransformDirection(m);
                this.setXYZ(i, _vector.X, _vector.Y, _vector.Z);
            }
            return this;
        }
        public override BufferAttribute setX(int index, double x)
        {
            if (this.normalized) x = Normalize(x, this.array);
            this.data.array[index * this.data.stride + this.offset] = x;
            return this;
        }
        public override BufferAttribute setY(int index, double y)
        {
            if (this.normalized) y = Normalize(y, this.array);
            this.data.array[index * this.data.stride + this.offset + 1] = y;
            return this;
        }
        public override BufferAttribute setZ(int index, double z)
        {
            if (this.normalized) z = Normalize(z, this.array);
            this.data.array[index * this.data.stride + this.offset + 2] = z;
            return this;
        }
        public override BufferAttribute setW(int index, double w)
        {
            if (this.normalized) w = Normalize(w, this.array);
            this.data.array[index * this.data.stride + this.offset + 3] = w;
            return this;
        }
        public override double getX(int index)
        {
            double x = this.data.array[index * this.data.stride + this.offset];
            if (this.normalized) x = Denormalize(x, this.array);
            return x;
        }
        public override double getY(int index)
        {
            double y = this.data.array[index * this.data.stride + this.offset + 1];
            if (this.normalized) y = Denormalize(y, this.array);
            return y;
        }
        public override double getZ(int index)
        {
            double z = this.data.array[index * this.data.stride + this.offset + 2];
            if (this.normalized) z = Denormalize(z, this.array);
            return z;
        }
        public override double getW(int index)
        {
            var _index = index * this.data.stride + this.offset + 3;
            if (_index >= this.data.array.Length)
                return MathEx.NaN;
            double w = this.data.array[_index];
            if (this.normalized) w = Denormalize(w, this.array);
            return w;
        }
        public override BufferAttribute setXY(int index, double x, double y)
        {
            index = index * this.data.stride + this.offset;
            if (this.normalized)
            {
                x = Normalize(x, this.array);
                y = Normalize(y, this.array);
            }
            this.data.array[index + 0] = x;
            this.data.array[index + 1] = y;
            return this;
        }
        public override BufferAttribute setXYZ(int index, double x, double y, double z)
        {
            index = index * this.data.stride + this.offset;
            if (this.normalized)
            {
                x = Normalize(x, this.array);
                y = Normalize(y, this.array);
                z = Normalize(z, this.array);
            }
            this.data.array[index + 0] = x;
            this.data.array[index + 1] = y;
            this.data.array[index + 2] = z;
            return this;
        }
        public override BufferAttribute setXYZW(int index, double x, double y, double z, double w)
        {
            index = index * this.data.stride + this.offset;
            if (this.normalized)
            {
                x = Normalize(x, this.array);
                y = Normalize(y, this.array);
                z = Normalize(z, this.array);
                w = Normalize(w, this.array);
            }
            this.data.array[index + 0] = x;
            this.data.array[index + 1] = y;
            this.data.array[index + 2] = z;
            this.data.array[index + 3] = w;
            return this;
        }
        public override BufferAttribute clone()
        {
            return new InterleavedBufferAttribute(data.clone() as InterleavedBuffer, this.itemSize, this.offset, this.normalized);
        }
        #endregion

    }
}
